unit Engine.Arrays;

interface

{$POINTERMATH ON}

type
  ArrayOfFloat = array of Single;
  ArrayOfInt = array of Integer;
  ArrayOfUInt = array of Cardinal;
  ArrayOfUByte = array of Byte;
  ArrayOfFloat16 = array [0..15] of Single;

  TArray<T> = class
  private
    FData: ^T;
    FDataSize: Integer;
    FCount: Integer;
  protected
  public
    constructor Create(const InitialSize: Integer = 16);
    destructor Destroy(); override;

    procedure Clear();

    procedure Add(const Value: T);
    function Remove(): T;
    procedure Delete(); overload;
    procedure Delete(const I: Integer); overload;

    procedure Shrink();

    procedure Grow();
    procedure SetCapacity(const NewSize: Integer);

    function GetData(const I: Integer): T; inline;
    procedure SetData(const I: Integer; const Value: T); inline;

    property Data[const I: Integer]: T read GetData write SetData; default;

    property Count: Integer read FCount;
  end;

implementation

uses
  Engine.Math;

{ TArrayWithLast<T> }

constructor TArray<T>.Create;
begin
  inherited Create();
  FDataSize:=InitialSize;
  FData:=AllocMem(FDataSize*SizeOf(T));
  FCount:=0;
end;

destructor TArray<T>.Destroy;
begin
  FreeMem(FData);
  inherited;
end;

function TArray<T>.GetData(const I: Integer): T;
begin
  Result:=T(Pointer(Integer(FData)+I*SizeOf(T))^)
          //FData[I];
end;

procedure TArray<T>.Grow;
begin
  SetCapacity(FDataSize shl 1);
end;

procedure TArray<T>.SetData(const I: Integer; const Value: T);
var
  S: Integer;
begin
  if I>=FDataSize then
  begin
    S:=FDataSize shl 1;
    if S>I then
      SetCapacity(S)
    else
      SetCapacity(I)
  end;
  Move(Value, T(Pointer(Integer(FData)+I*SizeOf(T))^), SizeOf(T));
end;

procedure TArray<T>.SetCapacity;
begin
  FDataSize:=NewSize;
  ReallocMem(FData, FDataSize*SizeOf(T))
end;

procedure TArray<T>.Add(const Value: T);
begin
  SetData(FCount, Value);
  Inc(FCount);
end;

procedure TArray<T>.Clear;
begin
  FCount:=0;
end;

procedure TArray<T>.Delete;
begin
  Dec(FCount);
end;

procedure TArray<T>.Delete(const I: Integer);
var
  J: Integer;
begin
  for J := I to FCount - 2 do
//    FData[J]:=FData[J+1];
    Move(T(Pointer(Integer(FData)+(J+1)*SizeOf(T))^),
      T(Pointer(Integer(FData)+J*SizeOf(T))^), SizeOf(T));
//    T(Pointer(Integer(FData)+J*SizeOf(T))^):=T(Pointer(Integer(FData)+(J+1)*SizeOf(T))^);
  Dec(FCount);
end;

function TArray<T>.Remove: T;
begin
  Result:=T(Pointer(Integer(FData)+FCount*SizeOf(T))^);
  Dec(FCount);
end;

procedure TArray<T>.Shrink;
begin
  SetCapacity(FCount);
end;

end.
